CSU 1724 相等距离的和(线段树)

题意:

$给定1个空的升序集合A,集合元素下标从1开始,给出1个距离L,有三种操作:$
$add x:向集合中加入一个元素,数据保证这个元素不在集合中$
$del x:从集合中删除一个元素,数据保证这个元素存在集合中$
$sum x:输出A_x+A_{x+L}+A_{x+2L}+……(0< x\le L)的值$

分析:

$线段树,把下标搞成从0开始的简单一点$
$每个节点维护cnt:=元素个数,sum[i]:=下标\%L=i的值的和$
$向上合并时先拷贝左儿子的sum,右儿子的sum根据左儿子元素个数计算新余数累加到当然节点$
$然后对于sum操作的答案就是sum[1][x-1]$

代码:

//
//  Created by TaoSama on 2016-04-28
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

typedef long long LL;
int n, L;
int cnt[N << 2];
LL sum[N << 2][5];
vector<int> xs;

void build(int l, int r, int rt) {
    cnt[rt] = 0;
    for(int i = 0; i < L; ++i) sum[rt][i] = 0;
    if(l == r) return;
    int m = l + r >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
}

void up(int rt) {
    int ls = rt << 1, rs = ls | 1;
    cnt[rt] = cnt[ls] + cnt[rs];

    int offset = cnt[ls];
    for(int i = 0; i < L; ++i) sum[rt][i] = sum[ls][i];
    for(int i = 0; i < L; ++i) sum[rt][(i + offset) % L] += sum[rs][i];
}

void update(int o, int v, int l, int r, int rt) {
    if(l == r) {
        cnt[rt] = v;
        sum[rt][0] = v * xs[l - 1];
        return;
    }
    int m = l + r >> 1;
    if(o <= m) update(o, v, l, m, rt << 1);
    else update(o, v, m + 1, r, rt << 1 | 1);
    up(rt);
}

int op[N], a[N];

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    while(scanf("%d%d", &n, &L) == 2) {
        xs.clear();
        for(int i = 1; i <= n; ++i) {
            char cmd[10]; scanf("%s%d", cmd, a + i);
            if(*cmd == 's') op[i] = 2;
            else {
                xs.push_back(a[i]);
                op[i] = *cmd == 'a';
            }
        }
        sort(xs.begin(), xs.end());
        xs.resize(unique(xs.begin(), xs.end()) - xs.begin());
        build(1, xs.size(), 1);

        static int kase = 0;
        printf("Case %d:\n", ++kase);
        for(int i = 1; i <= n; ++i) {
            if(op[i] != 2) {
                int o = lower_bound(xs.begin(), xs.end(), a[i]) - xs.begin() + 1;
                update(o, op[i], 1, xs.size(), 1);
            } else printf("%lld\n", sum[1][a[i] - 1]);
        }
    }
    return 0;
}